{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 259,
   "metadata": {},
   "outputs": [],
   "source": [
    "import backtrader as bt  \n",
    "import pandas as pd\n",
    "from datetime import datetime\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from backtrader_plotting import Bokeh\n",
    "from backtrader_plotting.schemes import Tradimo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 接收数据到变量dataframe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 260,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_stock = pd.read_csv('data/sh1.csv') # 股票日数据\n",
    "data_signals = pd.read_csv('data/bwwmacd.csv') # 股票指标数据(大智慧导出)\n",
    "\n",
    "selected_columns = ['日期', '开盘', '最高', '最低', '收盘', '成交量',]\n",
    "data_stock = stock[selected_columns]\n",
    "selected_columns = ['日期','MA1','MA2','MA3','S' ]\n",
    "data_signals = data_signals[selected_columns]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 修正列表名称和时间索引"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 261,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 改变列名称\n",
    "data_stock.columns = ['date', 'open', 'high', 'low', 'close', 'volume']\n",
    "data_signals.columns = ['date', 'M5', 'M10', 'M20','MA']\n",
    "\n",
    "# 日期列转换时间类型\n",
    "data_stock['date'] = pd.to_datetime(data_stock['date'])\n",
    "data_signals['date'] = pd.to_datetime(data_signals['date'])\n",
    "\n",
    "# 时间索引\n",
    "data_stock.index = pd.to_datetime(data_stock['date'])\n",
    "data_signals.index = pd.to_datetime(data_signals['date'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 262,
   "metadata": {},
   "outputs": [],
   "source": [
    "# backtrader投喂数据格式\n",
    "data_stock = data_stock.iloc[:, :6]\n",
    "data_stock['openinterest'] = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 263,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>date</th>\n",
       "      <th>open</th>\n",
       "      <th>high</th>\n",
       "      <th>low</th>\n",
       "      <th>close</th>\n",
       "      <th>volume</th>\n",
       "      <th>openinterest</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2024-06-14</th>\n",
       "      <td>2024-06-14</td>\n",
       "      <td>3020.96</td>\n",
       "      <td>3037.9</td>\n",
       "      <td>3011.58</td>\n",
       "      <td>3032.63</td>\n",
       "      <td>348746752.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                 date     open    high      low    close       volume  \\\n",
       "date                                                                    \n",
       "2024-06-14 2024-06-14  3020.96  3037.9  3011.58  3032.63  348746752.0   \n",
       "\n",
       "            openinterest  \n",
       "date                      \n",
       "2024-06-14             0  "
      ]
     },
     "execution_count": 263,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_stock.tail(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 264,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>date</th>\n",
       "      <th>M5</th>\n",
       "      <th>M10</th>\n",
       "      <th>M20</th>\n",
       "      <th>MA</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2024-06-14</th>\n",
       "      <td>2024-06-14</td>\n",
       "      <td>-1027</td>\n",
       "      <td>-1217.0</td>\n",
       "      <td>-1220.7</td>\n",
       "      <td>-440.7</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                 date    M5     M10     M20     MA\n",
       "date                                              \n",
       "2024-06-14 2024-06-14 -1027 -1217.0 -1220.7 -440.7"
      ]
     },
     "execution_count": 264,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_signals.tail(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# data_signals数据源添加生成指标列="
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 265,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化一个新的列来存储金叉死叉信号  \n",
    "data_signals['signal'] = 1 \n",
    "\n",
    "# 使用shift函数来访问前一行的值，然后设置新的信号列  \n",
    "# 注意这里我们使用了向量化操作，而不是循环  \n",
    "data_signals.loc[(data_signals['M5'] > data_signals['M10'].shift(1)) &   \n",
    "               (data_signals['M5'].shift(1) < data_signals['M10'].shift(2)),   \n",
    "               'signal'] = 2 \n",
    "  \n",
    "data_signals.loc[(data_signals['M5'] < data_signals['M10'].shift(1)) &   \n",
    "               (data_signals['M5'].shift(1) > data_signals['M10'].shift(2)),   \n",
    "               'signal'] =0 \n",
    "  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 266,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>date</th>\n",
       "      <th>M5</th>\n",
       "      <th>M10</th>\n",
       "      <th>M20</th>\n",
       "      <th>MA</th>\n",
       "      <th>signal</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2024-06-14</th>\n",
       "      <td>2024-06-14</td>\n",
       "      <td>-1027</td>\n",
       "      <td>-1217.0</td>\n",
       "      <td>-1220.7</td>\n",
       "      <td>-440.7</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                 date    M5     M10     M20     MA  signal\n",
       "date                                                      \n",
       "2024-06-14 2024-06-14 -1027 -1217.0 -1220.7 -440.7       1"
      ]
     },
     "execution_count": 266,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_signals.tail(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义二个数据类-股票和指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 267,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyStockData(bt.feeds.PandasData):  # MyStockData 类定义了如何从Pandas DataFrame中提取股票数据。\n",
    "    # params 元组指定了日期、开盘价、最高价、最低价、收盘价和交易量（如果有的话）在DataFrame中的列索引。\n",
    "    params = (  \n",
    "        ('datetime', 0),  # 日期在DataFrame中的列索引  \n",
    "        ('open', 1),      # 开盘价在DataFrame中的列索引  \n",
    "        ('high', 2),      # 最高价在DataFrame中的列索引  \n",
    "        ('low', 3),       # 最低价在DataFrame中的列索引  \n",
    "        ('close', 4),     # 收盘价在DataFrame中的列索引  \n",
    "        ('volume', 5),    # 交易量在DataFrame中的列索引（如果有的话）  \n",
    "        ('openinterest', -1),    # 交易量在DataFrame中的列索引（如果有的话）  \n",
    "    )  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 268,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义一个自定义数据源类  \n",
    "class MySignalData(bt.feeds.PandasData):  # MySignalData 类用于处理信号数据。\n",
    "    #lines = ('M5','M10','M20','MA','signal',)  # lines = ('signal',) 是一个元组的示例，\n",
    "    # 指定了日期和信号在DataFrame中的列索引。\n",
    "    params = (  \n",
    "        ('datetime', 0),  # 日期在DataFrame中的列索引\n",
    "        ('M5', 1), # 假设'M5'是某种信号，这里重命名以避免混淆  \n",
    "        ('M10', 2), # 同上  \n",
    "        ('M20', 3), # 同上 \n",
    "        ('MA', 4), # 同上 \n",
    "        ('signal', 5),    # 信号在DataFrame中的列索引，假设1为买入，-1为卖出，0为不操作  \n",
    "    )  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#  添加数据源  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 269,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.MySignalData at 0x218f62e9820>"
      ]
     },
     "execution_count": 269,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "datafeed_stock = MyStockData(dataname=data_stock)  \n",
    "datafeed_signal = MySignalData(dataname=data_signals)\n",
    "\n",
    "# 将数据源添加到cerebro  \n",
    "# # 创建Cerebro引擎  \n",
    "cerebro = bt.Cerebro()  \n",
    "\n",
    "cerebro.adddata(datafeed_stock, name=\"000001\")  \n",
    "cerebro.adddata(datafeed_signal, name='data')  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义一个自定义指标类\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 270,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义一个自定义指标类  \n",
    "class ExternalIndicator(bt.Indicator):  \n",
    "    lines = ('ext_ind',)  # 指标名称  \n",
    "  \n",
    "    def __init__(self):  \n",
    "        super(ExternalIndicator, self).__init__()  \n",
    "  \n",
    "    def next(self):  \n",
    "        # 假设外部数据源的指标值存储在'IndicatorValue'列\n",
    "        self.lines.ext_ind[0] = self.params.data.lines.signal[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 创建自定义指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 271,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建自定义指标\n",
    "ext_ind = ExternalIndicator(datafeed_signal)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 272,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将自定义指标添加到引擎（不需要再次指定名称，因为它已经在Indicator类中定义了）  \n",
    "cerebro.addindicator(ext_ind, 'ext_ind') "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 273,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个简单的策略  \n",
    "class SimpleStrategy(bt.Strategy):  \n",
    "    def next(self):  \n",
    "        print[self.indicators.ext_ind[0]]\n",
    "        # 简单的交易逻辑  \n",
    "        if self.indicators.ext_ind[0] == 2:  # 假设指标值大于0时买入  \n",
    "            self.buy()  \n",
    "        elif self.indicators.ext_ind[0] == 0:  # 指标值小于0时卖出  \n",
    "            self.sell()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 274,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'<=' not supported between instances of 'str' and 'int'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_13000\\4073724797.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[1;31m# 运行回测\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mcerebro\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      6\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      7\u001b[0m \u001b[1;31m# 绘制图表\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\ProgramData\\Anaconda3\\lib\\site-packages\\backtrader\\cerebro.py\u001b[0m in \u001b[0;36mrun\u001b[1;34m(self, **kwargs)\u001b[0m\n\u001b[0;32m   1130\u001b[0m             \u001b[1;31m# let's skip process \"spawning\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1131\u001b[0m             \u001b[1;32mfor\u001b[0m \u001b[0miterstrat\u001b[0m \u001b[1;32min\u001b[0m \u001b[0miterstrats\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1132\u001b[1;33m                 \u001b[0mrunstrat\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrunstrategies\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0miterstrat\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1133\u001b[0m                 \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrunstrats\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mrunstrat\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1134\u001b[0m                 \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_dooptimize\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\ProgramData\\Anaconda3\\lib\\site-packages\\backtrader\\cerebro.py\u001b[0m in \u001b[0;36mrunstrategies\u001b[1;34m(self, iterstrat, predata)\u001b[0m\n\u001b[0;32m   1257\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1258\u001b[0m                 \u001b[1;32mfor\u001b[0m \u001b[0mindcls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mindargs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mindkwargs\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mindicators\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1259\u001b[1;33m                     \u001b[0mstrat\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_addindicator\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mindcls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0mindargs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mindkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1260\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1261\u001b[0m                 \u001b[1;32mfor\u001b[0m \u001b[0mancls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0manargs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mankwargs\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0manalyzers\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\ProgramData\\Anaconda3\\lib\\site-packages\\backtrader\\strategy.py\u001b[0m in \u001b[0;36m_addindicator\u001b[1;34m(self, indcls, *indargs, **indkwargs)\u001b[0m\n\u001b[0;32m    224\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    225\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_addindicator\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mindcls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0mindargs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mindkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 226\u001b[1;33m         \u001b[0mindcls\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mindargs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mindkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    227\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    228\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_addanalyzer_slave\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mancls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0manargs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mankwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\ProgramData\\Anaconda3\\lib\\site-packages\\backtrader\\lineseries.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, ago, line)\u001b[0m\n\u001b[0;32m    546\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    547\u001b[0m         \u001b[1;31m# else -> assume type(ago) == int -> return LineDelay object\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 548\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mLineDelay\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_getline\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mline\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mago\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0m_ownerskip\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    549\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    550\u001b[0m     \u001b[1;31m# The operations below have to be overriden to make sure subclasses can\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\ProgramData\\Anaconda3\\lib\\site-packages\\backtrader\\linebuffer.py\u001b[0m in \u001b[0;36mLineDelay\u001b[1;34m(a, ago, **kwargs)\u001b[0m\n\u001b[0;32m    635\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    636\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mLineDelay\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ma\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mago\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 637\u001b[1;33m     \u001b[1;32mif\u001b[0m \u001b[0mago\u001b[0m \u001b[1;33m<=\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    638\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0m_LineDelay\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ma\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mago\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    639\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mTypeError\u001b[0m: '<=' not supported between instances of 'str' and 'int'"
     ]
    }
   ],
   "source": [
    "# 添加策略到引擎  \n",
    "cerebro.addstrategy(SimpleStrategy)  \n",
    "  \n",
    "# 运行回测  \n",
    "cerebro.run()  \n",
    "  \n",
    "# 绘制图表  \n",
    "cerebro.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个简单的策略  \n",
    "class SimpleStrategy(bt.Strategy):  \n",
    "    def next(self):  \n",
    "        # 简单的交易逻辑  \n",
    "        if self.indicators.ext_ind[0] > 0:  # 假设指标值大于0时买入  \n",
    "            self.buy()  \n",
    "        elif self.indicators.ext_ind[0] < 0:  # 指标值小于0时卖出  \n",
    "            self.sell()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Another value\n"
     ]
    }
   ],
   "source": [
    "class DataRepository:  \n",
    "    def __init__(self):  \n",
    "        self.data_store = {  \n",
    "            'data': 'Some value associated with \"data\"',  \n",
    "            'otherdata': 'Another value'  \n",
    "        }  \n",
    "  \n",
    "    def getdatabyname(self, name):  \n",
    "        return self.data_store.get(name)  \n",
    "  \n",
    "# 使用示例  \n",
    "repo = DataRepository()  \n",
    "value = repo.getdatabyname('otherdata')  \n",
    "print(value)  # 输出: Some value associated with \"data\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "start = datetime(2024,6,3)\n",
    "end = datetime(2024,6,7)\n",
    "# 创建PandasData对象data\n",
    "data = bt.feeds.PandasData(dataname=stock, fromdate=start, todate=end) # 第10行\n",
    "# 创建Cerebro对象cerebro作为回测引擎\n",
    "cerebro = bt.Cerebro()\n",
    "cerebro.adddata(data)# 通过cerebro的adddata方法关联PandasData对象data，\n",
    "cerebro.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('[1]', cerebro.datas[0].datetime.array)\n",
    "print('[2]', cerebro.datas[0].close.array)\n",
    "print('[3]', cerebro.datas[0].high.array)\n",
    "print('[4]', cerebro.datas[0].low.array)\n",
    "print('[5]', cerebro.datas[0].open.array)\n",
    "print('[6]', cerebro.datas[0].volume.array)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Example 3-1\n",
    "print('[1]', data.lines._getlines())# 获取当前类和父类提供的数据线名称集合；\n",
    "print('[2]', data.lines._getlinesbase())# 获取父类提供的数据线名称集合；\n",
    "print('[3]', data.lines._getlinesextra())# 获取当前类和父类指定可以额外添加的数据线的数量总和；\n",
    "print('[4]', data.lines._getlinesextrabase())# 获取父类指定可以额外添加的数据线的数量总和。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lines类就是用于管理多根数据线的数据结构。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from backtrader.feeds import PandasData\n",
    "from backtrader import Lines, LineBuffer\n",
    "\n",
    "class MyPandasData(PandasData):\n",
    "    lines = ('turnover', )\n",
    "    extralines = 1\n",
    "    linesoverride = False\n",
    "    linealias = {'turnover': 'hs'}\n",
    "# MyPandasData.lines是一个Lines类的子类，它提供的数据线名称数量为8，额外可添加数据线的数量为1。\n",
    "print('[1]', MyPandasData.lines)\n",
    "print('[2]', issubclass(MyPandasData.lines, Lines))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('[1]', MyPandasData.lines._getlines())\n",
    "print('[2]', MyPandasData.lines._getlinesbase())\n",
    "print('[3]', MyPandasData.lines._getlinesextra())\n",
    "print('[4]', MyPandasData.lines._getlinesextrabase())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_extraline = LineBuffer()\n",
    "my_lines = MyPandasData.lines([my_extraline])\n",
    "\n",
    "print('[1]', my_extraline)\n",
    "print('[2]', len(MyPandasData.lines._getlines()))\n",
    "print('[3]', MyPandasData.lines._getlinesextra())\n",
    "\n",
    "for k, v in enumerate(my_lines.lines, start = 1):\n",
    "    print(k, v)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
